﻿using System;
using System.Collections;
using System.Collections.Generic;
using Netbits.Common.Threading;

namespace Netbits.Common.Collections
{
	/// <summary>
	/// Represent a locked queue
	/// </summary>
	/// <typeparam name="TItem">TypeOf Item</typeparam>
	public class LockedQueue<TItem> : IEnumerable<TItem>, ICollection, IEnumerable
	{
		#region Private Variables

		/// <summary>
		/// The queue of TItems.
		/// </summary>
		protected readonly Queue<TItem> _Queue;
		/// <summary>
		/// The lock instance.
		/// </summary>
		protected readonly Lock _Lock;

		#endregion

		#region Constructor

		/// <summary>
		/// Create a new instance of the locked queue
		/// </summary>
		public LockedQueue() : this( new Lock( true ) )
		{
		}

		/// <summary>
		/// Create a new instance of the locked queue with specified Lock instance.
		/// </summary>
		public LockedQueue( Lock LockInstance_ )
		{
			_Queue = new Queue<TItem>();
			_Lock = LockInstance_;
		}

		#endregion

		#region Public Properties

		/// <summary>
		/// Returns the number of items in the queue
		/// </summary>
		/// <value>Number of items</value>
		public int Count
		{
			get
			{
				try
				{
					_Lock.EnterReadLock();
					return _Queue.Count;
				}
				finally
				{
					_Lock.ExitReadLock();
				}
			}
		}

		/// <summary>
		/// Return true if the queue is thread-safe. In this implementation this property returns always true
		/// </summary>
		public virtual bool IsSynchronized
		{
			get
			{
				return true;
			}
		}

		/// <summary>
		/// Return the Lock instance.
		/// </summary>
		public virtual object SyncRoot
		{
			get
			{
				return _Lock;
			}
		}

		#endregion

		#region Public Functions

		/// <summary>
		/// Add the item to the end of the queue.
		/// </summary>
		/// <param name="Item_">Item_ to add</param>
		public virtual void Enqueue( TItem Item_ )
		{
			try
			{
				_Lock.EnterWriteLock();
				_Queue.Enqueue( Item_ );
			}
			finally
			{
				_Lock.ExitWriteLock();
			}
		}

		/// <summary>
		/// Remove and return the item at the beginning of the queue.
		/// </summary>
		/// <returns>The item that is removed from queue, otherwise default(TItem)</returns>
		public virtual TItem Dequeue()
		{
			try
			{
				_Lock.EnterWriteLock();

				if( _Queue.Count == 0 )
					return default( TItem );

				return _Queue.Dequeue();
			}
			finally
			{
				_Lock.ExitWriteLock();
			}
		}

		/// <summary>
		/// Remove all items from the queue.
		/// </summary>
		public virtual void Clear()
		{
			try
			{
				_Lock.EnterWriteLock();
				_Queue.Clear();
			}
			finally
			{
				_Lock.ExitWriteLock();
			}
		}

		/// <summary>
		/// Determines whether an item is in the queue.
		/// </summary>
		/// <param name="Item_">The item to located in the queue</param>
		/// <returns>true if Item_ is found in the queue, otherwise false</returns>
		public virtual bool Contains( TItem Item_ )
		{
			try
			{
				_Lock.EnterReadLock();
				return _Queue.Contains( Item_ );
			}
			finally
			{
				_Lock.ExitReadLock();
			}
		}

		/// <summary>
		/// Returns the item at the beginning of the queue without removing it.
		/// </summary>
		/// <returns>The item at the beginning of the queue</returns>
		public virtual TItem Peek()
		{
			try
			{
				_Lock.EnterReadLock();
				return _Queue.Peek();
			}
			finally
			{
				_Lock.ExitReadLock();
			}
		}

		/// <summary>
		/// Set the capacity to the actual number of items in the queue. 
		/// </summary>
		public virtual void TrimExcess()
		{
			try
			{
				_Lock.EnterWriteLock();
				_Queue.TrimExcess();
			}
			finally
			{
				_Lock.ExitWriteLock();
			}
		}

		/// <summary>
		/// Returns a new locked-enumerator that iterates through the queue.
		/// </summary>
		/// <returns>Locked enumerator</returns>
		public virtual IEnumerator<TItem> GetEnumerator()
		{
			return new LockedEnumerator<TItem>( _Queue, _Lock );
		}

		/// <summary>
		/// Returns a new locked-enumerator that iterates through the queue.
		/// </summary>
		/// <returns>Locked enumerator</returns>
		IEnumerator IEnumerable.GetEnumerator()
		{
			return new LockedEnumerator<TItem>( _Queue, _Lock );
		}

		/// <summary>
		/// Copies the items of the queue to a new array
		/// </summary>
		/// <returns></returns>
		public virtual TItem[] ToArray()
		{
			try
			{
				_Lock.EnterReadLock();
				return _Queue.ToArray();
			}
			finally
			{
				_Lock.ExitReadLock();
			}
		}

		/// <summary>
		/// Copies the items of the queue to an one-dimensional array, starting at the specified index.
		/// </summary>
		/// <param name="Array_">The one-dimensional array that is the destination of the items.</param>
		/// <param name="Index_">The zero-based index in Array_ at witch copying begins.</param>
		public virtual void CopyTo( Array Array_, int Index_ )
		{
			try
			{
				_Lock.EnterReadLock();

				int index = Index_;
				int maxItems = Array_.Length - index;
				foreach( TItem item in _Queue )
				{
					if( maxItems == 0 )
						break;

					Array_.SetValue( item, index++ );
					--maxItems;
				}
			}
			finally
			{
				_Lock.ExitReadLock();
			}
		}

		#endregion
	}
}
